/*
 *  2010-2021   @date: 2024-12-29 20:19:31
 * author : Ronbinson    [ drv_uart ]
 */

#include <drv_uart.h>
#include <stdbool.h>
#include <stdio.h>
#include <string.h>

#include "FreeRTOS.h"
#include "task.h"

#define UART_TX_GPIO_CLK RCU_GPIOA
#define UART_TX_GPIO_PROT GPIOA
#define UART_TX_GPIO_PIN GPIO_PIN_9

#define UART_RX_GPIO_CLK RCU_GPIOA
#define UART_RX_GPIO_PROT GPIOA
#define UART_RX_GPIO_PIN GPIO_PIN_10

#define UART_CLK RCU_USART0
#define UART_COM USART0
#define UART_COM_IRQn USART0_IRQn

#define UART_BPS_SET 921600U

#define CFG_USE_UART3 (1)

void UartPeriphInit(void)
{
    rcu_periph_clock_enable(RCU_DMA0);
    rcu_periph_clock_enable(UART_TX_GPIO_CLK);
    rcu_periph_clock_enable(UART_RX_GPIO_CLK);
    rcu_periph_clock_enable(UART_CLK);

    gpio_init(UART_TX_GPIO_PROT, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, UART_TX_GPIO_PIN);
    gpio_init(UART_RX_GPIO_PROT, GPIO_MODE_IN_FLOATING, GPIO_OSPEED_50MHZ, UART_RX_GPIO_PIN);

    usart_deinit(UART_COM);
    usart_baudrate_set(UART_COM, UART_BPS_SET);
    usart_receive_config(UART_COM, USART_RECEIVE_ENABLE);
    usart_transmit_config(UART_COM, USART_TRANSMIT_ENABLE);
    usart_enable(UART_COM);

    nvic_irq_enable(UART_COM_IRQn, 4, 0);

    /* enable the USART receive timeout and configure the time of timeout */
    usart_receiver_timeout_enable(UART_COM);
    usart_receiver_timeout_threshold_config(UART_COM, 30);
}

#if CFG_USE_UART3
/* retarget the C library printf function to the USART */
int fputc(int ch, FILE *f)
{
    usart_data_transmit(UART3, (uint8_t)ch);
    while (RESET == usart_flag_get(UART3, USART_FLAG_TBE));
    return ch;
}

#else

/* retarget the C library printf function to the USART */
#if defined(__CC_ARM)
/*  重定向fputc到USART0 */
int fputc(int ch, FILE *f)
{
    usart_data_transmit(UART_COM, (uint8_t)ch);
    while (RESET == usart_flag_get(UART_COM, USART_FLAG_TBE));
    return ch;
}
#elif defined(__GNUC__)
int _write(int fd, char *ptr, int len)
{
    for (int i = 0; i < len; i++) {
        usart_data_transmit(UART_COM, *(ptr + i));
        while (RESET == usart_flag_get(UART_COM, USART_FLAG_TBE));
    }

    return len;
}
#endif

#endif

#if !CFG_USE_UART3
/*  重定向fgetc到USART0 */
int fgetc(FILE *f)
{
    while (RESET == usart_flag_get(UART_COM, USART_FLAG_RBNE));
    return usart_data_receive(UART_COM);
}
#else /* 用 uart3 接收PC */
/*  重定向fgetc到USART0 */
int fgetc(FILE *f)
{
    while (RESET == usart_flag_get(UART3, USART_FLAG_RBNE));
    return usart_data_receive(UART3);
}
#endif

/*  重定向fgets到USART0 */
char *fgets(char *str, int size, FILE *stream)
{
    int sizeBkup = size;
    int i = 0;
    int ch;

    if (size <= 0 || !stream)
        return NULL;  // 检查输入参数的有效性

    while (--size > 0) {
        ch = fgetc(stream);  // 从文件流中读取一个字符
        if (ch == EOF)
            break;  // 到达文件结束或读取出错

        /* 比较两次时间 */
        static TickType_t last_tick;
        TickType_t current_tick = xTaskGetTickCount();
        if (current_tick - last_tick > 10) {
            i = 0;
            size = sizeBkup;
            memset(&str[0], 0, size);
        }
        last_tick = current_tick;

        if (ch == '>') {
            str[i] = ch;
            str[i + 1] = '\0';
            printf("PC tx str=%s\r\n", str);
            return str;
        }
        if (ch == '\n') {
            str[i] = '\0';
            printf("PC tx str=%s\r\n", str);
            return str;
        }

        str[i++] = ch;
    }

    if (i > 0 && ch != EOF) {
        str[i] = '\0';
    }
    if (i == 0 && ch == EOF) {
        return NULL;
    }

    return str;
}

void PlatformTestUartSendData(uint8_t data)
{
    usart_data_transmit(UART_COM, data);
    while (RESET == usart_flag_get(UART_COM, USART_FLAG_TBE));
}

void DemoTestMain(void)
{
    /* enable GPIO clock */
    rcu_periph_clock_enable(RCU_GPIOC);

    /* enable USART clock */
    rcu_periph_clock_enable(RCU_UART3);

    /* connect port to USARTx_Tx */
    gpio_init(GPIOC, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_10);

    /* connect port to USARTx_Rx */
    gpio_init(GPIOC, GPIO_MODE_IN_FLOATING, GPIO_OSPEED_50MHZ, GPIO_PIN_11);

    /* USART configure */
    usart_deinit(UART3);
    usart_baudrate_set(UART3, UART_BPS_SET);
    usart_receive_config(UART3, USART_RECEIVE_ENABLE);
    usart_transmit_config(UART3, USART_TRANSMIT_ENABLE);
    usart_enable(UART3);

    printf("\n\ra [uart3] transmit test example success!\n\r");
}
